﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Text;

namespace BusinessObjects.Encryption
{
    public static class DesCrypt
    {
        private const string KEY = "faa6a81474619122e4c982152806920c6a39922430f4be78";
        private const string IV = "dafe0f81449b892b";

        private static readonly TripleDESCryptoServiceProvider Des3;

        static DesCrypt()
        {
            Des3 = new TripleDESCryptoServiceProvider { Mode = CipherMode.CBC };
        }

        private static byte[] HexStringToBytes(string hexString)
        {
            byte[] bytes = new byte[hexString.Length / 2];
            for (int i = 0; i < hexString.Length / 2; i++)
            {
                bytes[i] = byte.Parse(hexString.Substring(i * 2, 2), NumberStyles.HexNumber);
            }
            return bytes;
        }

        private static string BytesToHexString(IEnumerable<byte> bytes)
        {
            StringBuilder stringBuilder = new StringBuilder();
            foreach (byte b in bytes)
            {
                stringBuilder.AppendFormat("{0:X2}", b);
            }
            return stringBuilder.ToString();
        }

        private static string Encrypt(string data, string key = null, string iv = null)
        {
            if (key == null)
            {
                key = KEY;
            }
            if (iv == null)
            {
                iv = IV;
            }

            byte[] byteData = Encoding.ASCII.GetBytes(data);
            byte[] byteKey = HexStringToBytes(key);
            byte[] byteIv = HexStringToBytes(iv);

            using (MemoryStream stream = new MemoryStream())
            {
                using (
                    CryptoStream cryptoStream = new CryptoStream(stream, Des3.CreateEncryptor(byteKey, byteIv),
                                                                 CryptoStreamMode.Write))
                {
                    Process(cryptoStream, byteData);
                }
                return BytesToHexString(stream.ToArray());
            }
        }

        private static void Process(CryptoStream cryptoStream, byte[] byteData)
        {
            cryptoStream.Write(byteData, 0, byteData.Length);
            cryptoStream.FlushFinalBlock();
            cryptoStream.Close();
        }

        private static string Decrypt(string data, string key = null, string iv = null)
        {
            if (key == null)
            {
                key = KEY;
            }
            if (iv == null)
            {
                iv = IV;
            }

            byte[] byteData = HexStringToBytes(data);
            byte[] byteKey = HexStringToBytes(key);
            byte[] byteIv = HexStringToBytes(iv);

            using (MemoryStream stream = new MemoryStream())
            {
                using (
                    CryptoStream cryptoStream = new CryptoStream(stream, Des3.CreateDecryptor(byteKey, byteIv),
                                                                 CryptoStreamMode.Write))
                {
                    Process(cryptoStream, byteData);
                }
                return Encoding.ASCII.GetString(stream.ToArray());
            }
        }

        public static string EncryptId(object id, string tableName)
        {
            string s = id + "|" + tableName;
            return Encrypt(s);
        }

        public static TKey DecryptId<TKey>(string str)
        {
            string s = Decrypt(str);
            return (TKey)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFrom(s.Substring(0, s.IndexOf("|")));
        }
    }
}